package com.warm.base.design.s_proxy;

import java.lang.reflect.Proxy;

/**
 * @Date: 2019/11/22 10:40
 * @Author: LChuang
 * @Description: 代理模式(结构型)
 *
 *      为其他对象提供一种代理以控制对这个对象的访问。
 */
public class Client {

    /**
     * Subject: 抽象主题角色：真实主题与代理主题的共同接口。
     * RealSubject: 真实主题角色：定义了代理角色所代表的真实对象。
     * Proxy: 代理主题角色：含有对真实主题角色的引用，代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作，而不是单纯返回真实的对象。
     */
    public static void main(String[] args) {
        // 1. static proxy
        /**
         * 优点：可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
         * 缺点：我们得为每一个服务都得创建代理类，工作量太大，不易管理。同时接口一旦发生改变，代理类也得相应修改。
         */
        Subject subject = new RealSubject();
        StaticProxy staticProxy = new StaticProxy(subject);
        staticProxy.operator();

        // 2. dynamic proxy
        /**
         * 在动态代理中我们不再需要再手动的创建代理类，我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建
         */
        /**
         * ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
         * Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
         * InvocationHandler:指定动态处理器，执行目标对象的方法时,会触发事件处理器的方法
         */
        Subject dyProxySub = (Subject) Proxy.newProxyInstance(
                Subject.class.getClassLoader(),
                new Class[]{Subject.class},
                new DynamicProxyHandler(subject));
        dyProxySub.operator();

        Subject dyProxySub1 = (Subject) Proxy.newProxyInstance(
                Subject.class.getClassLoader(),
                Subject.class.getInterfaces(),
                new DynamicProxyHandler(subject));
        dyProxySub1.operator();

        // 3. cglib proxy
        /**
         * JDK实现动态代理需要实现类通过接口定义业务方法，对于没有接口的类，如何实现动态代理呢，这就需要CGLib了。
         * JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
         * CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高，但是CGLIB创建代理对象时所花费的时间却比JDK多得多。
         * 所以对于单例的对象，因为无需频繁创建对象，用CGLIB合适，反之使用JDK方式要更为合适一些。
         * 同时由于CGLib由于是采用动态创建子类的方法，对于final修饰的方法无法进行代理。
         */
        CglibProxy cglibProxy = new CglibProxy();
        RealSubject realCgProxy = (RealSubject) cglibProxy.getInstance(subject);
        realCgProxy.operator();

    }
}
